#!/usr/bin/perl

# ---------- Init variables -------
#my $version = "0.0001";
# ---------- external readable parameters -------
## Functions
##-------------------------------------------------------
#
# stict syntax checking.
use strict;
use CGI qw(param);
use SIM_settings;
use SIM_base;
use SIM_cgi;
use SIM_nodeInfo;
use SIM_report;
use SIM_updateInfo;

# Startupscript casetool, part of Sipman.

my $tool = $ARGV[0];
my $action = $ARGV[1];
my $option1 = $ARGV[2];
if ( "$option1" eq "none" ) {
  $option1 = "";
}
my $option2 = $ARGV[3];
my $option3 = $ARGV[4];
my $option4 = $ARGV[5];
my $option5 = $ARGV[6];
my $option6 = $ARGV[7];
my $option7 = $ARGV[8];

#print("tool=$tool, action=$action, option1=$option1, option2=$option2 option3=$option3 option4=$option4<BR>");

my $httpReF = $ENV{'HTTP_REFERER'};
my $httpScriptName = $ENV{'httpScriptName'};
my $systemHtml = $ENV{'SIM_SYSTEM'} || die "Oops no env found for SIM_SYSTEM.";

sub walkSubnetEntries {
  # Walk the subnets
  my $network = "@_[0]";
  my $cacheFile = "@_[1]";
  my ( $ip1, $ip2, $ip3 ) = split('\.', $network);
  my $ipDir = getIpDir( $network );
  if ( -d $ipDir ) {
    chdir $ipDir;
    my @dirUnsortEntries = <*>;
    my @dirEntries = sort { $a <=> $b } @dirUnsortEntries; # numerical sort
    if ( "$ip3" ne "" ) {
      open(OUT, ">>$SIMparam{'SIMtmpDir'}/$cacheFile") || die "cannot append $cacheFile: $!";
      foreach my $entry (@dirEntries) {
        if ( -d "$ipDir/$entry" ) {
	  print OUT "$ip1.$ip2.$ip3.$entry\n";
	}
      }
      close OUT;
    } elsif ( "$ip1" eq "" ) {
      foreach my $entry (@dirEntries) {
        walkSubnetEntries( $entry, $cacheFile );
      }
    } else {
      foreach my $entry (@dirEntries) {
        walkSubnetEntries( "$network.$entry", $cacheFile );
      }
    }
  }
}

sub displaySubnetEntries {
  my $network = "@_[0]";
  if (( $network eq "none" ) or ( $network eq "root" )) {
    $network = "";
  }
  my @colors = qw( #FFFF66 #FFFF99 #FFFFCC );
  my @ips = split('\.', $network);
  $network = "";
  my $testip = $ips[0];
  my $last = "no";
  my $dispEntry;
  print("<TABLE>");
  foreach my $entry (@colors) {
    if ( $last eq "no" ) {
      print("<TR BGCOLOR=$entry><TD ALIGN=center>");
      my $ipDir = getIpDir( $network );
 #    print("$ipDir");
      if ( -d $ipDir ) {
        if ( $network eq "" ) {
          &printEntry2("All","List subnet $dispEntry", "mon+displaysubnet+ip+$testip", "mon+displaysubnet+ip+root", " ", "line", "", "");
        }
        chdir $ipDir;
        my @dirUnsortEntries = <*>;
        my @dirEntries = sort { $a <=> $b } @dirUnsortEntries; # numerical sort
        foreach my $dirEntry ( @dirEntries ) {
          if ( $network eq "" ) {
            $dispEntry = $dirEntry;
          } else {
            $dispEntry = "$network.$dirEntry";
          }
          if ( $entry eq "#FFFFCC" ) {
            &printEntry2("$dispEntry","List subnet $dispEntry", "mon+displaysubnet+ip+$testip", "mon+displaysubnet+ip+$dispEntry", " ", "line", ".", ".");
          } else {
            &printEntry2("$dispEntry","List subnet $dispEntry", "mon+subnets+ip+$testip", "mon+subnets+ip+$dispEntry", " ", "line", ".", "");
            &printEntry2("(*)","List subnet $dispEntry", "mon+displaysubnet+ip+$testip", "mon+displaysubnet+ip+$dispEntry", " ", "line", "", ".");
          }
#         print(" $dirEntry ");
        }
      }
      if ( $ips[0] eq "" ) {
        $last = "yes";
      } else {
        if ( $network eq "" ) {
          $network = $ips[0];
        } else {
          $network = "$network.$ips[0]";
        }
        shift(@ips);
        $testip = "$testip.$ips[0]";
      }
      print("</TD></TR>");
    }
  }
  print("</TABLE>");
  # testing with this table
}

sub dispCacheTable {
  my $cacheFile = "@_[0]";
  my $sortKey = "@_[1]";
  my $cmdStr;
  if ( "$sortKey" eq "mac" ) {
    $cmdStr = "sort -k 2";
  } elsif ( "$sortKey" eq "type" ) {
    $cmdStr = "sort -f -k 3";
  } elsif ( "$sortKey" eq "status" ) {
    $cmdStr = "sort -k 4";
  } elsif ( "$sortKey" eq "dns" ) {
    $cmdStr = "sort -f -k 6";
  } elsif ( "$sortKey" eq "host" ) {
    $cmdStr = "sort -f -k 7";
  } elsif ( "$sortKey" eq "oid" ) {
    $cmdStr = "sort -f -k 8";
  } elsif ( "$sortKey" eq "int" ) {
    $cmdStr = "sort -nr -k 9";
  } elsif ( "$sortKey" eq "switchport" ) {
    $cmdStr = "sort -f -k 11";
  } else {
    $cmdStr = "cat";
  }
  my @lines = ` $cmdStr $cacheFile `;
  foreach my $entry (@lines) {
    my ( $ipAddr, $rest ) = split(' ', $entry);
    printNodeLine($ipAddr);
  }
}

sub pingNode {
  my $ipAddr = "@_[0]";
  print("<PRE>");
  system(" ping -c 30 $ipAddr ");
  print("</PRE>");
}

sub displayMenu{
  print("<FONT COLOR=#666666>");
  printMenu("mon","line", $tool, $action, "$option1+$option2+$option3");
# my $test = testIfIp( $option1);
# if ( "$test" eq "oke" ) {
#   print("</FONT></TD></TR><TR BGCOLOR=#EEEEEE><TD COLSPAN=3><FONT COLOR=#666666><CENTER>");
#   printMenu("mon-nodestatus","line", $tool, $action, "$option1+$option2+$option3");
# }
  print("</FONT></TD></TR></TABLE><CENTER>");
}

sub nodestatus {
  #print("New nodestatus, under devellopment (<A HREF=$httpScriptName?mon+nodestatusOld+$option1>Old</A>).<BR>");
  my $option1 = "@_[0]";
  my $option2 = "@_[1]";
  my $option3 = "@_[2]";
  my $option4 = "@_[3]";
  my $option5 = "@_[4]";
  system(" $SIMparam{'SIMdispNodeInfo'} mon nodestatus $option1 $option2 $option3 $option4 $option5");
}

sub changeNodeStatus {
  my $newStatus = $_[0];
  my $ipAddr = $_[1];
# print("changeNodeStatus: newStatus=$newStatus, ipAddr=$ipAddr. ");
  if (( $newStatus eq "Unmanaged") or ( $newStatus eq "Managed") or ( $newStatus eq "Confirmed")) {
    &updateNodeStatus( $ipAddr, "$remoteUser", $newStatus );
  } elsif ( $newStatus eq "ConfirmAll") {
    my $ipDir = &getIpDir($ipAddr);
    if ( -f "$ipDir/firstmac.txt" ) {
      my $firstMac = &catFileLine("$ipDir/firstmac.txt");
      my @files = <$SIMparam{'SIMmacDatab'}/$firstMac/ipint-*>;
      foreach my $entry (@files) {
        my $info = catFileLine($entry);
        my ( $testIp, $rest ) = split(' ', $info);
        my $testIpDir = &getIpDir($testIp);
        my $info = catFileLine("$testIpDir/pollstatus.txt");
        my ( $timeStamp, $status ) = split(' ', $info);
        if ( $status eq "Down" ) {
          &updateNodeStatus( $testIp, "$remoteUser", "Confirmed");
        }
      }
    }
  } else {
    print("<H2>Sorry status $newStatus not supported for $ipAddr.</H2>");
  }
  &nodestatus( $ipAddr, "info" );
}

sub nodestatusOld {
  my $option1 = "@_[0]";
  my $option2 = "@_[1]";
  my $option3 = "@_[2]";
  system(" $SIMparam{'SIMoldMonitorPlugin'} nodestatus $option1 $option2 $option3 ");
}

sub updateOui {
  my $oui = "@_[0]";
  my $info = param("oui");
  if ( $info eq "" ) {
    $info = catFileLine("$SIMparam{'SIMmacOuiDir'}/$oui/vendor");
  } else {
    testMkDir("$SIMparam{'SIMmacOuiDir'}/$oui");
    updField( "127.0.0.1", $remoteUser, "oui id for $oui", "$SIMparam{'SIMmacOuiDir'}/$oui/vendor", $info);
  }
  print("
    <FORM method=post Action=$httpScriptName?mon+updateOui+$oui>
        Update the vendor name for oui $oui:
        <INPUT NAME=oui Size=20 Type=text VALUE=\"$info\">
        <INPUT TYPE=submit Value=Update>
        </FORM>
    ");
}

sub addNote {
  my $note = param("note");
  $note =~ s/</&lt;/g;
  $note =~ s/>/&gt;/g;
# $note =~ s/.{120}/$&<BR>/sg; # this should break the lines, but it does not
# $note =~ s/  / &nbsp;/g;
# Improved handling for white space (so we dont need the pre anymore
  $note =~ s/  /&nbsp;&nbsp;/g;
  $note =~ s/\r\n /<BR>&nbsp;/g;
  $note =~ s/\r\n/<BR>/g;
# $input =~ s/^\s+|\s+$//g (white space begin en einde verwijderen)

  if ( "$note" ne "" ) {
    my $userName = catFileLine("$SIMparam{'SIMpasswdUserDir'}/$remoteUser/userName");
#   logLine("$option1","note","Note-$remoteUser","$userName<PRE>$note</PRE>");
#   logLine("$option1","note","Note-$remoteUser","$userName<BR>$note");
#   Fixed width font used for screen captures.
    logLine("$option1","note","Note-$remoteUser","$userName<BR><font face=\"Consolas, Lucida Console, Monaco, Andale Mono, ProFont, Anonymous, Courier\">$note</FONT>");
  }
  nodestatus($option1,$option2,$option3);
}

sub runDiscover {
  my $ipAddr = "@_[0]";
  print("<H2>Discovering nodes on $ipAddr</H2></CENTER>\n");
  print("Running: $SIMparam{'SIMdiscoverNodes'} pollNode $ipAddr<HR>");
  system(" $SIMparam{'SIMdiscoverNodes'} pollNode $ipAddr ");
}

sub printSubnetList {
  # this module needs more work to be migrated to perl.
  my $ipAddr = $_[0];
  print("<TABLE><TR BGCOLOR=#FFFF66 ALIGN=center><TD>
     <A HREF=$httpScriptName?mon+displaysubnet+ip+root>All networks</A> / ");
  if ( -d "$SIMparam{'SIMipDatabase'}" ) {
    chdir $SIMparam{'SIMipDatabase'};
    my @ipList = <*>;
    my @sorted = sort { $a <=> $b } @ipList;
    foreach my $entry (@sorted) {
      if ( -f $entry ) {
        print(" <FONT COLOR=red>$entry</FONT>");
        unlink( $entry );
      } else {
        print(". <A HREF=$httpScriptName?mon+subnets+ip+$entry>$entry</A><A HREF=/sipman3-cgi/nph-sipman3.cgi?mon+displaysubnet+ip+$entry>(*)</A> .\n");
      }
    }
  }
  print("</TD></TR></TABLE>");
}

sub displayDomainLogging {
  my $dispLog = $_[0];
  my $numLines = $_[1];
  if ( $numLines eq "" ) { $numLines = 50; }
  my $logType = $_[2];
  if ( $logType eq "" ) { $logType = "dnsname"; }
  my $repeats = $_[3];
  if ( $repeats eq "" ) { $repeats = 20; }
  my @allLogging = ();
  my $groupName = catFileLine("$SIMparam{'SIMpasswdUserDir'}/$remoteUser/group");
  my $userLevel = catFileLine("$SIMparam{'SIMpasswdGroupDir'}/$groupName/accessLevel-$SIMparam{'SIMmanDomain'}");
  if ( $userLevel eq "" ) {
    $userLevel = catFileLine("$SIMparam{'SIMpasswdGroupDir'}/$groupName/accessLevel-all");
  }
  my $logDir = $SIMparam{'SIMlogDir'};
  my $errorLogging = catFileLine("$SIMparam{'SIMpasswdGroupDir'}/$groupName/errorLogging");
  my $otherLogging = catFileLine("$SIMparam{'SIMpasswdGroupDir'}/$groupName/otherLogging");
  if ( ! -d $SIMparam{'SIMmessagesDir'} ) {
    print("<H2>Sorry, no logging directory SIMmessagesDir=$SIMparam{'SIMmessagesDir'}.</H2>")
  } elsif ( $otherLogging ne "all" ) {
    @allLogging = split(' ', "$errorLogging $otherLogging");
  } else {
    @allLogging = split(' ', "$errorLogging");
    chdir $SIMparam{'SIMmessagesDir'};
    my @fileList = <messages-*-log>;
    foreach my $entry (@fileList) {
      #print("fileListEntry=$entry. ");
      my ( $message, $type, $rest ) = split('-', $entry);
      push( @allLogging, $type );
    }
  }
  if ( $userLevel eq "" ) {
    print("Please contact your administrator, to update the userlevel.");
  } else {
    my %allowedLogs = ();
    # display selection line
    if ( $#allLogging ne -1 ) {
      print("<TABLE BGCOLOR=#EEEEFF WIDTH=100%><TR><TD ALIGN=center>Node types: ");
      foreach my $entry (@allLogging) {
        if ( -f "$SIMparam{'SIMmessagesDir'}/messages-$entry-log" ) {
          if ( $allowedLogs{$entry} eq "" ) {
            $allowedLogs{$entry} = "found";
            if ( $dispLog eq "" ) {
              $dispLog = $entry;
            }
            printEntry2("$entry","Display logging for $entry", "mon+log+default+100+$dispLog", "mon+log+default+100+$entry", "", "line", ".", "");
          }
        }
      }
      print("<BR>Logging:");
      my @lineList = ( 50, 100, 500, 1000, 2000, 5000 );
      foreach my $entry (@lineList) {
        printEntry2("$entry", "$entry lines", "mon+log+$logType+$numLines+$dispLog", "mon+log+$logType+$entry+$dispLog", "", "line", ".", "");
      }
      print(", Type:");
      printEntry2("Ip addres", "Ip addres", "mon+log+$logType+$numLines+$dispLog", "mon+log+ipaddr+$numLines+$dispLog", "", "line", "", "");
      printEntry2("Dns name", "Dns name", "mon+log+$logType+$numLines+$dispLog", "mon+log+dnsname+$numLines+$dispLog", "", "line", "/", "");
      print(", Repeats:");
      printEntry2("no", "no", "mon+log+$logType+$numLines+$dispLog+$repeats", "mon+log+$logType+$numLines+$dispLog+20", "", "line", "", "");
      printEntry2("yes", "yes", "mon+log+$logType+$numLines+$dispLog+$repeats", "mon+log+$logType+$numLines+$dispLog+1", "", "line", "/", "");
      print("</TD></TR></TABLE>");
      if ( $allowedLogs{$dispLog} eq "found") {
        print("<TABLE>");
        system(" $SIMparam{'SIMformatLogging'} $SIMparam{'SIMmessagesDir'}/messages-$dispLog-log $userLevel $logType $numLines $repeats ");
        print("</TABLE>");
      }
    }
  }
}

sub displayStatusInfo {
  printSubnetList;
  # status info for monitored devices
  my $groupName = catFileLine("$SIMparam{'SIMpasswdUserDir'}/$remoteUser/group");
  my $monDevList = catFileLine("$SIMparam{'SIMpasswdGroupDir'}/$groupName/devicesMonitored");
  if ( $monDevList ne "" ) {
#   print("testing $monDevList. ");
    system(" $SIMparam{'SIMdisplayNodeStatus'} $monDevList ");
  }
  &displayDomainLogging;
}

sub searchform {
  print("<TABLE WIDTH=100% BGCOLOR=#EEEEEE><TR><TD ALIGN=center><FONT COLOR=#888888>Seedtool:</FONT>");
  &printEntry2("ipAddress","use the seed tool to search for info in the IP database.", "mon+$action+ip", "mon+searchSeed+ip", " ", "line", "", "");
  &printEntry2("macAddress","use the seed tool to search for mac adresses in the IP database.", "mon+$action+mac", "mon+searchSeed+mac", " ", "line", "/", "");
  &printEntry2("dnsName","Search for ip adresses, based on resolved dns reccords.", "mon+$action+ip", "mon+searchSeed+dns", " ", "line", "/", "");
  &printEntry2("searchIndex","Search the index file for multiple keys.", "mon+$action+ip", "mon+searchSeed+searchIndex", " ", "line", "/", "");
  print("</TD></TR></TABLE>");
  print("<H2>Use the seed tools, or:</H2>");
  #
  if ( &testMenuLevel("mon+searchCache") eq "oke" ) {
    print("<TABLE BGCOLOR=#FFFFDD><TR><TD>
        <FONT SIZE=+2>Search for IP related info.</FONT>
        <P>Use this to to find any part of the ip related info (e.g. ip address, mac address, hostname, vendor type, .....).<BR>
        Use this tool to find info in the cache tables.<BR>
        Due to the nature of cache files (which are updated periodicaly, you may not find the latest data
        <FORM method=post Action=$httpScriptName?mon+searchCache+search-$remoteUser>
        Search for IP-info:
        <INPUT NAME=searchstring Size=20 Type=text>
        <INPUT TYPE=submit Value=Search>
        </FORM>
           </TD></TR></TABLE>");
  }
  if ( &testMenuLevel("mon+macsearch") eq "oke" ) {
    print("<P><TABLE BGCOLOR=#FFFFDD><TR><TD>
        <FONT SIZE=+2>Search for Mac related info in the mac database.</FONT>
        <P>Enter an part of an mac address to search (syntax xx.xx.xx.xx.xx.xx or xx:xx:xx:xx:xx:xx).<BR> 
           This search is usefull if you are looking for an mac address, not associated to an ip address,
           like an switch mac.
        <FORM method=post Action=$httpScriptName?mon+macsearch>
        Search for Mac-info:
        <INPUT NAME=searchstring Size=20 Type=text>
        <INPUT TYPE=submit Value=Search>
        </FORM>
          </TD></TR></TABLE>");
  }
}

sub searchSeed {
  my $tool = $_[0];
  my $action = $_[1];
  my $searchType = $_[2];
  my $result = $_[3];
  # also allow input from the command line, to search for.
  if (( $result eq "" ) or ( $result eq "none" )) {
    $result = param("seedList");
  } else {
    print("<H2>Searching for $result</H2>");
  }
  my $cacheFile = "searchSeed-$remoteUser";
  if ( $result eq "" ) {
    if ( $searchType eq "ip" ) {
      print("<B>Enter your IP seedlist below</B> (this tool will search for ip adresses within any text, as long as there is white space around the ip adresses):");
    } elsif ( $searchType eq "mac" ) {
      print("<B>Enter your Mac seedlist below</B> (this tool will search for mac adresses within any text,<BR>
               as long as there is white space around the ip adresses). Supported syntax xx:xx:xx:xx:xx or xxxx.xxxx.xxxx.");
    } elsif ( $searchType eq "dns" ) {
      print("<B>Enter your DNS seedlist below</B> This tool will try to resolve each word found against the dns servers.");
    } elsif ( $searchType eq "searchIndex" ) {
      print("<B>Enter the various search criteria below</B> This tool will search the IP index for each of the words defined.");
    } else {
      print("<H2>Sorry, seed type not yet defined,</H2>");
    }
    print("<FORM method=post Action=$httpScriptName?$tool+searchSeed+$searchType>
       <INPUT TYPE=hidden NAME=action VALUE=test>
         <TEXTAREA NAME=\"seedList\" ROWS=20 COLS=100>
         </TEXTAREA><BR>
          <INPUT TYPE=submit Value=\"Process\">
       </FORM>");
  } else {
    open( OUT, ">$SIMparam{'SIMtmpDir'}/$cacheFile" ) || die "Problems creating cachfile $cacheFile.";
    if ( $searchType eq "ip" ) {
      my @info = split(' ', $result);
      foreach my $entry (@info) {
        my $result = testIfIp( $entry );
        if ( "$result" eq "oke" ) {
          print OUT ("$entry\n");
        }
      }
    } elsif ( $searchType eq "dns" ) {
      my @info = split(' ', $result);
      foreach my $entry (@info) {
        my $ipAddr = getAreccord($entry);
        my $result = testIfIp( $ipAddr );
        if ( "$result" ne "oke" ) {
          $ipAddr = $entry;
        }
        print OUT ("$ipAddr\n");
      }
    } elsif (( $searchType eq "searchIndex" ) or ( $searchType eq "mac" )) {
      my @info = split(' ', $result);
      foreach my $entry (@info) {
        if ( $searchType eq "mac" ) {
          # if we are searching for mac adresses, skip the rest.
          $entry = testIfMac( $entry );
#         print("entry = \"$entry\". ");
          if ( "$entry" eq "noMac" ) {
            $entry = "";
          }
        }
        if ( $entry ne "" ) {
          my @found = ` grep -i \"$entry\" $SIMparam{'SIMipSearchIndex'} `;
          foreach my $regel (@found) {
            chomp $regel;
            if ( $regel ne "" ) {
              print OUT ("$regel\n");
            }
          }
        }
      }
    } else {
      print("searchSeed: searchType $searchType not yet defined.");
      exit;
    }
    close OUT;
    searchIndex( "mon", "listCache", $cacheFile );
  }
  
}

# ------------------------------------- Main ---------------------------------------

&displayMenu;
#print("action = $action");

if ( "$action" eq "subnets" ) {
  &displaySubnetEntries( $option2 );
  print("<H2>Select an range above.</H2>");
} elsif ( "$action" eq "displaysubnet" ) {
  &displaySubnetEntries( $option2 );
  my $tmpFile = "ip-$option2-$remoteUser";
  my $cacheFile = "ip-$option2";
  if ( -f "$SIMparam{'SIMtmpDir'}/$tmpFile" ) {
    unlink "$SIMparam{'SIMtmpDir'}/$tmpFile";
  }
  if ( $option2 eq "root" ) {
    $option2 = "";
  }
  walkSubnetEntries($option2, $tmpFile);
  system(" mv $SIMparam{'SIMtmpDir'}/$tmpFile $SIMparam{'SIMtmpDir'}/$cacheFile");
  searchIndex( "mon", "listCache", $cacheFile );
} elsif (( "$action" eq "listCache" ) or ( "$action" eq "updCache" ) or ( "$action" eq "generateCsv" )) {
  searchIndex( $tool, $action, $option1, $option2, $option3 );
} elsif ( "$action" eq "searchform" ) {
  searchform;
} elsif ( "$action" eq "searchCache" ) {
  searchIndex( $tool, $action, $option1 );
} elsif ( "$action" eq "searchSeed" ) {
  searchSeed( $tool, $action, $option1, $option2 );
} elsif ( "$action" eq "switchinfo" ) {
  print("</CENTER><PRE>");
  system(" $SIMparam{'SIMswitchinfo'} node $option1 ");
  print("</PRE><CENTER>");
} elsif ( "$action" eq "nodestatusOld" ) {
  nodestatusOld($option1,$option2,$option3);
} elsif ( "$action" eq "discover" ) {
  runDiscover($option1);
} elsif ( "$action" eq "nodestatus" ) {
  nodestatus($option1,$option2,$option3,$option4,$option5,$option6);
} elsif ( "$action" eq "updateOui" ) {
  updateOui($option1,$option2,$option3);
} elsif ( "$action" eq "addNote" ) {
  addNote($option1,$option2,$option3);
} elsif ( "$action" eq "statusInfo" ) {
  displayStatusInfo;
} elsif ( "$action" eq "changeStatus" ) {
  &changeNodeStatus($option1, $option2);
} elsif ( "$action" eq "pingNode" ) {
  pingNode($option1);
} elsif ( "$action" eq "log" ) {
  displayDomainLogging( $option3, $option2, $option1, $option4 );
} else {
  print("<B>old monitor</B>");
  system(" $SIMparam{'SIMoldMonitorPlugin'} $action $option1 $option2 $option3 $option4");
}
